package tesis.common.security;

import tesis.domain.security.UsuarioSeguridad;
import tesis.domain.security.UsuarioSiged;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.NoResultException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * Esta clase es un UserDetailsService Personalizada en la cual se puede definir
 * la forma en que el password y demás datos de un usuario debe ser recuperado,
 * pudiendo esto ser implementado para usar LDAP, BD, etc. El
 * @Component("customUserDetailsService") instancia un bean de esta clase en el
 * contexto, el cual sera usado en el applicationContext-base.xml: <pre
 * style="background-color:#ddd;border-color:#fff;"> ... <br/>
 * &lt;security:authentication-manager&gt; <br/>
 * &lt;security:authentication-provider
 * user-service-ref="customUserDetailsService" /&gt; <br/>
 * &lt/security:authentication-manager&gt; <br/> ...
 * </pre>
 */
@Component("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService {

    private final static Logger LOG = LoggerFactory.getLogger(CustomUserDetailsService.class);
    //@PersistenceContext(unitName = "seguridadPU")
    private EntityManager em;
    //@Inject
    //PropertiesService properties;
    @Inject
    SeguridadService seguridadService;

    /**
     * Este método para devolver los datos de un Usuario a partir de su nombre
     * de Usuario
     *
     * @param userName, es el nombre de usuario que se quiere buscar sus datos
     * @return devuelve una instancia de la clase UserDetails con los datos del
     * userName seteados
     */
    @Transactional
    @Override
    public UserDetails loadUserByUsername(String userName) {
        LOG.info("loading User By User Name");
        Object result = null;
        try {
            result = this.em.createNamedQuery("UsuarioSeguridad.findByUsuario").setParameter("usuario", userName).getSingleResult();
        } catch (EntityNotFoundException ex1) {
            throw new UsernameNotFoundException("usuario: '" + userName + "' no existe", ex1);
        } catch (NoResultException ex2) {
            throw new UsernameNotFoundException("usuario: '" + userName + "' no existe", ex2);
        } catch (Exception ex3) {
            throw new DataAccessException("error bd", ex3) {
            };
        }

        UsuarioSeguridad user = (UsuarioSeguridad) result;
        LOG.debug("usuario intentando logearse, username:" + userName + ", password:" + seguridadService.desencriptar(userName, user.getClave()));
        
        List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
        grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_USER"));
        grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_EAU"));
//        grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_JOR"));
//        grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
        
        
        /*if (user.getIdUsuario() != properties.getIdUsuarioSigedAdministrador().intValue()) {
            throw new UsernameNotFoundException("Usuario '" + userName + "' no tiene permisos para ingresar a este sistema");
        }*/
        return new User(user.getUsuario(), user.getClave(), true, true, true, true, grantedAuthorities);
    }

    public UsuarioSeguridad getUsuarioSeguridad(String userName) {
        LOG.info("getUsuarioSeguridad:" + userName);
        Object result = null;
        try {
            result = this.em.createNamedQuery(UsuarioSeguridad.FIND_BY_USUARIO).setParameter("usuario", userName).getSingleResult();
        } catch (EntityNotFoundException ex1) {
            LOG.info("error: " + ex1.getMessage());
            throw new UsernameNotFoundException("usuario: '" + userName + "' no existe", ex1);
        } catch (NoResultException ex2) {
            LOG.info("error: " + ex2.getMessage());
            throw new UsernameNotFoundException("usuario: '" + userName + "' no existe", ex2);
        } catch (Exception ex3) {
            LOG.info("error: " + ex3.getMessage());
            throw new DataAccessException("error bd", ex3) {
            };
        }
        return (UsuarioSeguridad) result;
    }

    public UsuarioSiged getUsuarioSiged(String userName) {
        LOG.info("getUsuarioSeguridad:" + userName);
        Object result = null;
        try {
            result = this.em.createNamedQuery(UsuarioSiged.FIND_BY_USUARIO).setParameter("usuario", userName).getSingleResult();

        } catch (EntityNotFoundException ex1) {
            LOG.info("error: " + ex1.getMessage());
            throw new UsernameNotFoundException("usuario: '" + userName + "' no existe", ex1);
        } catch (NoResultException ex2) {
            LOG.info("error: " + ex2.getMessage());
            throw new UsernameNotFoundException("usuario: '" + userName + "' no existe", ex2);
        } catch (Exception ex3) {
            LOG.info("error: " + ex3.getMessage());
            throw new DataAccessException("error bd", ex3) {
            };
        }
        return (UsuarioSiged) result;
    }
}
